package top.hkyzf.study.j2se.stream;

import org.junit.Test;
import top.hkyzf.study.j2se.lambda.methodref.Employee;
import top.hkyzf.study.j2se.lambda.methodref.EmployeeData;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * Stream 的中间操作
 * @author 朱峰
 * @date 2021-8-11 18:35
 */
public class StreamAPITest1 {
    /**
     * 1-筛选与切片
     */
    @Test
    public void test1 () {
        List<Employee> employeeList = EmployeeData.getEmployee();
        // filter(Predicate p)——接收 Lambda ， 从流中排除某些元素。
        Stream<Employee> stream = employeeList.stream();
        // 查询员工表中薪资大于 7000 的
        stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);

        System.out.println();
        // limit(n)——载断流，使其元素不超过给定数量。
        employeeList.stream().limit(3).forEach(System.out::println);

        System.out.println();
        // skip(n)——跳过元素，返回一个扔掉了前 n 个元素的流。若流中元素不足 n 个，则返回一个空流，与 limit(n) 互补
        employeeList.stream().skip(3).forEach(System.out::println);

        System.out.println();
        // distinct()——筛选，通过流所生成元素的 hashCode() 和 equals() 去除重复元素
        employeeList.add(new Employee(1010, "刘强东", 40, 8000));
        employeeList.add(new Employee(1010, "刘强东", 41, 8000));
        employeeList.add(new Employee(1010, "刘强东", 40, 8000));
        employeeList.add(new Employee(1010, "刘强东", 40, 8000));
        employeeList.add(new Employee(1010, "刘强东", 40, 8000));
//        System.out.println(employeeList);
        employeeList.stream().distinct().forEach(System.out::println);
    }

    /**
     * 2-映射
     */
    @Test
    public void test2 () {
        // map(Function f)——接收一个函数作为参数，将元素转换成其他形式或提取信息，该函教会被应用到每个元素上，并将其映射成一个新的元素。
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd");
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
        // 练习1：获取员工姓名长度大于3的员工的姓名。
        List<Employee> employees = EmployeeData.getEmployee();
        // 方式一
        employees.stream().filter(emp -> emp.getName().length() > 3).forEach(emp -> System.out.println(emp.getName()));
        // 方式二
        employees.stream().map(Employee::getName).filter(name -> name.length() > 3).forEach(System.out::println);

        System.out.println("***************************");

        // 练习2
        Stream<Stream<Character>> streamStream = list.stream().map(StreamAPITest1::fromStringToStream);
        streamStream.forEach(stream -> {
            stream.forEach(System.out::println);
        });

        System.out.println("***************************");

        // flatMap(Function f)——接收一个函数作为参数，将流中的每个值都换成另一个流，然后把所有流连接成一个流。
        Stream<Character> characterStream = list.stream().flatMap(StreamAPITest1::fromStringToStream);
        characterStream.forEach(System.out::println);
    }

    // 将字符串中所有的字符组成的集合转换成对应的Stream实例
    private static Stream<Character> fromStringToStream(String str) {
        List<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();
    }

    /**
     * 用于理解 map 和 flatMap
     */
    @Test
    public void test3 () {
        ArrayList list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);

        ArrayList list2 = new ArrayList<>();
        list2.add(4);
        list2.add(5);
        list2.add(6);

        // 类比 map
        // list1.add(list2);
        // 类比 flatMap
        list1.addAll(list2);
        System.out.println(list1);
    }

    /**
     * 3-排序
     */
    @Test
    public void test4 () {
        // sorted() - 自然排序
        List<Integer> list = Arrays.asList(12,323,324,55,42,3,231,2,-123,-214);
        list.stream().sorted().forEach(System.out::println);

        // 抛异常，原因：Employee 没有实现 Comparable 接口
//        List<Employee> employees = EmployeeData.getEmployee();
//        employees.stream().sorted().forEach(System.out::println);

        // sorted(Comparator com) - 定制排序
        List<Employee> employees = EmployeeData.getEmployee();
        employees.stream().sorted((e1, e2) -> {
            int compare = Integer.compare(e1.getAge(), e2.getAge());
            if(compare != 0) {
                return compare;
            } else {
                return Double.compare(e1.getSalary(), e2.getSalary());
            }
        }).forEach(System.out::println);

    }
}
